<template>
  <form-item-wrapper
    :field="field"
    :rules="rules"
    :designer="designer"
    :design-state="designState"
    :parent-list="parentList"
    :parent-widget="parentWidget"
    :sub-form-row-id="subFormRowId"
    :sub-form-row-index="subFormRowIndex"
    :sub-form-col-index="subFormColIndex"
    :index-of-parent-list="indexOfParentList"
  >
    <el-tree-select
      ref="fieldEditor"
      class="full-width-input"
      v-model="fieldModel"
      :size="widgetSize"
      :data="sOptions"
      :loading="loading"
      :check-strictly="field.options.checkStrictly"
      :disabled="field.options.disabled"
      :clearable="field.options.clearable"
      :filterable="field.options.filterable"
      :current-node-key="fieldModel"
      :highlight-current="true"
      :defaultExpandedKeys="defaultExpandedKeys"
      :default-first-option="allowDefaultFirstOption"
      :automatic-dropdown="field.options.automaticDropdown"
      :multiple="field.options.multiple"
      :multiple-limit="field.options.multipleLimit"
      :placeholder="field.options.placeholder || i18nt('render.hint.selectPlaceholder')"
      :remote="field.options.remote" :remote-method="remoteMethod"
      @focus="handleFocusCustomEvent" @blur="handleBlurCustomEvent"
      @change="handleChange"
    >
    </el-tree-select>
  </form-item-wrapper>
</template>

<script>
  import FormItemWrapper from './form-item-wrapper'

  import i18n from "@/utils/i18n"

  import XEUtils from 'xe-utils'
  import emitter from '@/utils/emitter'

  import { getBaseDictData } from '@/api/api-setting.js'
  import { defAxios as request } from '@/utils/http'

  import fieldMixin from "@designer/form-widget/field-widget/fieldMixin";
  import { SelectUtils } from './config/select-utils.js'
  import { fieldBaseMixin } from './mixins'

  import { transformTreeSelect } from '@/utils/transform-utils'
  import { SelectDataType, SelectDictDataType } from '@/base/pojo/SelectDataType.js'

  export default {
    name: "tree-select-widget",
    componentName: 'FieldWidget',  //必须固定为FieldWidget，用于接收父级组件的broadcast事件
    mixins: [emitter, fieldMixin, i18n, fieldBaseMixin ],
    inject: ['enumsDataPools'],
    props: {
      field: Object,
      designer: Object,
      parentList: Array,
      parentWidget: Object,
      indexOfParentList: Number,
      /** 是否为设计状态 */
      designState: { type: Boolean, default: false },
      /* 子表单组件行索引，从0开始计数 */
      subFormRowIndex: { type: Number, default: -1 },
      /* 子表单组件列索引，从0开始计数 */
      subFormColIndex: { type: Number, default: -1 },
      /* 子表单组件行Id，唯一id且不可变 */
      subFormRowId: { type: String, default: '' },

    },
    components: {
      FormItemWrapper,
    },
    data() {
      return {
        rules: [],
        loading: false,
        showCode: true,
        sOptions: [],
        expandMap: {},
        fieldModel: null,
        currentNode: {},
        oldFieldValue: null, //field组件change之前的值
        defaultExpandedKeys: [],
      }
    },
    computed: {
      allowDefaultFirstOption() {
        return (!!this.field.options.filterable && !!this.field.options.allowCreate)
      },

      remoteMethod() {
        if (!!this.field.options.remote && !!this.field.options.onRemoteQuery) {
          return this.remoteQuery
        } else {
          return undefined
        }
      },

      filedOptions() {
        return this.field.options
      },
    },
    beforeCreate() {
      /* 这里不能访问方法和属性！！ */
    },

    created() {
      /* 注意：子组件mounted在父组件created之后、父组件mounted之前触发，故子组件mounted需要用到的prop
         需要在父组件created中初始化！！ */
      this.initOptionItems()
      this.initFieldModel()
      this.registerToRefList()
      this.initEventHandler()
      this.buildFieldRules()
      this.handleOnCreated()
    },
    beforeMount() {
      // 加载选框数据
      this.loadOptionsData()
    },
    mounted() {
      this.handleOnMounted()
    },
    beforeUnmount() {
      this.unregisterFromRefList()
    },
    watch: {
      'filedOptions.multiple': {
        handler(newValue, oldValue) {
          if (newValue) {
            this.fieldModel = []
          } else {
            this.fieldModel = undefined
          }
        }
      },
    },
    methods: {
      /**
       * 加载下拉数据
       *
       * @param condition 查询条件
       */
      loadOptionsData(condition) {
        // 设计状态不加载
        if (this.designState) return
        // 加载数据
        const { filedOptions } = this
        this.showCode = filedOptions.hasOwnProperty('showCode') ? filedOptions.showCode : true
        const { optionConfig, optionItemsSelect } = filedOptions
        const { mode: selectMode, fieldNames } = optionConfig
        if (SelectDataType.DICT.equals(selectMode)) {
          this.loadOptionDict(optionConfig.dictConfig, fieldNames, condition)
        } else if (SelectDataType.SERVE.equals(selectMode)) {
          this.loadOptionServe(optionConfig.serveConfig, fieldNames, condition)
        } else if (SelectDataType.STATIC.equals(selectMode)) {
          let optionItems = []
        if (optionItemsSelect && optionItemsSelect.length > 0) {
          optionItems = optionItemsSelect
        } else {
          optionItems = optionConfig.staticConfig ? optionConfig.staticConfig.optionItems : []
        }
          this.loadOptionStatic(optionItems, fieldNames)
        } else {
          this.sOptions = []
        }
      },
      /**
       * 加载静态数据
       * @param {Array} values 目标数据
       * @param {Object} props 替换字段 { label, value, children }
       */
      loadOptionStatic(values, props) {
        const transfResult = transformTreeSelect.transfData(XEUtils.clone(values || [], true), {
          type: 'static',
          props: props,
          showCode: this.showCode,
        })
        this.sOptions = transfResult.tranfData
        this.setOtherSelInfo(transfResult)
      },
      /**
       * 加载字典项目数据
       * @param {Object} dictConfig 字典项配置
       * @param {Object} props 字段属性配置
       * @param {Object} condition 查询条件
       */
      async loadOptionDict(dictConfig, props, condition) {
        const valid = SelectUtils.checkConfig(dictConfig)
        if (!valid) return
        const { dictType, dictParams } = dictConfig
        if (!dictConfig.dictName) return

        // 解析查询条件
        condition = this.parseQueryCondition(condition || dictParams, false)
        const { hooks }= this.getBusiConfig()
        if(hooks && hooks.useCryptoHook){
          condition = hooks.useCryptoHook().encryptDataByRSA(condition)
        }
        let resOptions = []
        // 基础数据]
        if (SelectDictDataType.BASE.equals(dictType)) {
          resOptions = await this.getOptionBase(dictConfig, props, condition)
        }
        // 枚举数据
        if (SelectDictDataType.ENUMS.equals(dictType)) {
          resOptions = this.getOptionEnum(dictConfig, props, condition)
        }
        this.sOptions = resOptions
      },
      /**
       * 加载数据（接口）
       * 
       * @param {Object} serveConfig 自定义请求项配置
       * @param {Object} props 字段属性配置
       * @param {Object} condition 额外条件
       */
      async loadOptionServe(serveConfig, props, condition={}) {
        const valid = SelectUtils.checkConfig(serveConfig)
        if (!valid) return
        let config = {
          url: serveConfig.url,
          method: serveConfig.method
        }
        let resultParams = this.parseQueryCondition(serveConfig.params)
        config[serveConfig.paramsType] = { ...resultParams, ...condition }
        if(config[serveConfig.paramsType].hasOwnProperty('condition')){
          const { hooks }= this.getBusiConfig()
          if(hooks && hooks.useCryptoHook){
            config[serveConfig.paramsType].condition = hooks.useCryptoHook().encryptDataByRSA(config[serveConfig.paramsType].condition)
          }
        }
        const resOptions = await this.getOptionServe(config, props)
        this.sOptions = resOptions
      },
      getOptionEnum({ dictName }, props) {
        const { enumsDataPools } = this
        const dictInfo = enumsDataPools ? enumsDataPools[dictName] : null
        let result = []
        // 本地枚举信息存在
        if (dictInfo) {
          let enumOptions = dictInfo.options
          if (enumOptions) {
            enumOptions = JSON.parse(JSON.stringify(enumOptions))
            result = Object.keys(enumOptions).map(key => enumOptions[key])
            const transfResult = transformTreeSelect.transfData(result, {
              type: SelectDictDataType.ENUMS.value, props: props, showCode: this.showCode,
            })
            result = transfResult.tranfData
            this.setOtherSelInfo(transfResult)
          }
        }
        return result
      },
      getOptionBase({ dictName: name }, props, condition) {
        this.loading = true
        return new Promise(resolve => {
          getBaseDictData(this.axiosConfig.request || request, {
            name, condition
          }).then(res => {
            const { code, data, msg } = res
            if (code === 200) {
              if (data) {
                const transfResult = transformTreeSelect.transfData(data, {
                  type: SelectDictDataType.BASE.value, props: props, showCode: this.showCode,
                })
                resolve(transfResult.tranfData)
                this.setOtherSelInfo(transfResult)
              } else {
                resolve([])
              }
            } else {
              console.error(msg)
              resolve([])
            }
          }).catch(err => {
            console.error(err)
            resolve([])
          }).finally(() => {
            this.loading = false
          })
        })
      },
      getOptionServe(config, props) {
        this.loading = true
        const reqAxios = this.axiosConfig.request || request
        return new Promise(resolve => {
          reqAxios(config).then(res => {
            const { code, data, msg } = res
            if (code === 200) {
              if (data) {
                const transfResult = transformTreeSelect.transfData(data, {
                  type: 'serve', props: props, showCode: this.showCode,
                })
                resolve(transfResult.tranfData)
                this.setOtherSelInfo(transfResult)
              } else {
                resolve([])
              }
            } else {
              console.error(msg)
              resolve([])
            }
          }).catch(err => {
            console.error(err)
            resolve([])
          }).finally(() => {
            this.loading = false
          })
        })
      },
      /**
       * 设置一些额外的信息
       * @param {Object} param 参数信息
       */
      setOtherSelInfo ({ nodeMap, expandMap }) {
        this.sNodeMap = nodeMap
        this.sExpandMap = expandMap
        // 针对单选的情况
        if (this.fieldModel) {
          this.currentNode = nodeMap[this.fieldModel]
          this.defaultExpandedKeys = expandMap[this.fieldModel]
        }
      },
      handleChange(value) {
        this.currentNode = this.sNodeMap[value]
        this.handleChangeEvent(value)
      }
    }
  }
</script>

<style lang="scss" scoped>
/* form-item-wrapper已引入，还需要重复引入吗？ */
@import "@/styles/global.scss";
  .full-width-input {
    width: 100% !important;
  }

</style>
